#include "BlockQueue.hpp"
#include "Task.hpp"

void *consumer(void *args)
{
    BlockQueue<CalTask> *cal_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_c_bq;
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_s_bq;

    while (true)
    {
        // 消费者进行消费
        CalTask cal_task;
        cal_bq->pop(&cal_task);
        std::string result = cal_task();
        std::cout << "消费任务 " << result << std::endl;

        // 消费者进行传递任务给save_bq
        SaveTask save_task(result, Save);
        save_bq->push(save_task);
        std::cout << "推送保存任务完成... " << std::endl;
    }
    return nullptr;
}

void *producer(void *args)
{
    BlockQueue<CalTask> *cal_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_c_bq;

    while (true)
    {
        // 生产者进行生产
        int x = rand() % 100 + 1;
        int y = rand() % 10;
        int opercode = rand() % oper.size();
        CalTask cal_task(x, y, oper[opercode], my_math);
        cal_bq->push(cal_task);
        std::cout << "生产任务 " << cal_task.toString() << std::endl;
        sleep(1);
    }
    return nullptr;
}

void *saver(void *args)
{
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(args))->_s_bq;
    while (true)
    {
        SaveTask save_task;
        save_bq->pop(&save_task);
        save_task();
        std::cout << "保存任务完成... " << std::endl;
    }
    return nullptr;
}

// 生产者，向任务队列输入数据
// 消费者，从任务队列拿取数据，处理后，输入到保存队列中
// 保存者，从保存队列中拿取数据并保存在文件中
void test()
{
    // 建立任务队列和保存队列
    BlockQueues<CalTask, SaveTask> *bqs = new BlockQueues<CalTask, SaveTask>;
    bqs->_c_bq = new BlockQueue<CalTask>;
    bqs->_s_bq = new BlockQueue<SaveTask>;

    pthread_t c[3], p[2], s;
    pthread_create(c, nullptr, consumer, (void *)bqs);
    pthread_create(c + 1, nullptr, consumer, (void *)bqs);
    pthread_create(c + 2, nullptr, consumer, (void *)bqs);

    pthread_create(p, nullptr, producer, (void *)bqs);
    pthread_create(p + 1, nullptr, producer, (void *)bqs);

    pthread_create(&s, nullptr, saver, (void *)bqs);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(c[2], nullptr);

    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);

    pthread_join(s, nullptr);
    delete bqs->_c_bq;
    delete bqs->_s_bq;
}

int main()
{
    srand((unsigned int)time(0) ^ getpid());
    test();
    return 0;
}
